package org.tri.gui.worker;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.tri.entity.Animal;
import org.tri.gui.worker.retrievers.DataRetriever;
import org.tri.model.AnimalesListTableModel;

/**
 * La clase {@code AnimalListFillWorker} es un worker especifico para cargar
 * el modelo de animales.
 * @author kiira
 * @version 1.0, Apr 7, 2012
 */
public class AnimalListFillWorker extends SwingWorker<List<Animal>, Object> {
    /** Modelo de animales a llenar. */
    private AnimalesListTableModel model;
    /** Retriever de donde obtener los animales. */
    private DataRetriever<Animal> retriever;
    /** Lista de listeners. */
    private List<TableFillListener> listenerList;

    /**
     * Inicializa el worker con un modelo y el retriever para obtener los animales.
     * @param model modelo a llenar.
     * @param retriever retriever para obtener los animales.
     */
    public AnimalListFillWorker( AnimalesListTableModel model, DataRetriever<Animal> retriever ) {
        this.model = model;
        this.retriever = retriever;
    
        this.listenerList = new ArrayList<TableFillListener>();
        
    }//end constructor
    
    /**
     * Agrega un listener a la lista de listeners del worker.
     * @param listener listener a agregar.
     */
    public final void addTableFillListener( TableFillListener listener ) {
        listenerList.add( listener );

    }//end método addTableFillListener

    /**
     * Elimina un listener de la lista de listeners el worker.
     * @param listener listener a eliminar.
     */
    public final void removeTableFillListener( TableFillListener listener ) {
        listenerList.remove( listener );

    }//end método removeTableFillListener

    /**
     * Este método es llamado cuando se terminó de realizar todas las acciones
     * necesarias para el llenado de la tabla (y cualquier otra tarea que 
     * realize el worker). Incluso si ocurrio un error, este método es llamado
     * de todas formas.
     * Informa a todos los listeners que se concluyó la tarea del worker.
     */
    private void fireDoneFillingTable() {
        for ( final TableFillListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.doneFillingTable();
                }

            } );

    }//end métdoo fireDoneFillingTable

    /**
     * Este método es llamado cuando ocurre un error al intentar llamar la 
     * tabla.
     * Informa a todos los listeners de lo ocurrido.
     * @param ex excepción generada por el error.
     */
    private void fireErrorFillingTable( final ExecutionException ex ) {
        for ( final TableFillListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.errorFillingTable( ex );
                }

            } );          
    
    }//end método errorFillingTable
            
    
    /**
     * {@inheritDoc} 
     */
    @Override
    protected List<Animal> doInBackground() throws Exception {
        return retriever.retrieveData();

    }//end método doInBackground 
    
    /**
     * Llena el modelo con los animales obtenidos, comprobando si ocurrío
     * algún tipo de error, generando los eventos correspondientes.
     */
    @Override
    protected void done() {
        super.done();

        try {
            //asignamos las filas
            model.setAnimales( get() );

        } catch ( InterruptedException ex ) {
        } catch ( ExecutionException ex ) {
            //enviamos el error a los listeners
            fireErrorFillingTable( ex );

        } finally {
            //enviamos el done a los listeners
            fireDoneFillingTable();

        }

    }//end método done

}//end clase AnimalListFillWorker
